#include "s-int.h"

#include "..\\..\\ShiningloreTribes_v3\\ref\\rijndael\\rijndael-alg-fst.c"

// rijn passcode
static unsigned char cipher[] = {0x6F, 0x35, 0x77, 0x82, 0x3B, 0xAE, 0x2B, 0x15, 0x8A, 0xC6, 0xA0, 0x24, 0x33, 0xA6, 0x5B, 0x4D};

// -> FE 00 13 02 FF 03 79 01 55
// <- 0F FC ED F0 0C F6 8E FA A1
void EncryptPackage(char* buf, int len)
{
	char* p = buf;
	int j = len;

	while(j--)
	{
		*p = ~*p++;
	}

	
	p--;
	j = len;
	char t = *buf & 0xF, c;

	while(j--)
	{
		c = *p & 0xF;
		*p = t | (((*p >> 4) & 0xF) << 4);
		t = c;
		p--;
	}
}

// -> 0F FC ED F0 0C F6 8E FA A1
// <- FE 00 13 02 FF 03 79 01 55
void DecryptPackage(char* buf, int len)
{
	char* p = buf;
	int j = len;
	char t = *(p + len - 1) & 0xF, c;

	while(j--)
	{
		c = *p & 0xF;
		*p = t | (((*p >> 4) & 0xF) << 4);
		t = c;
		p++;
	}

	p--;
	j = len;

	while(j--)
	{
		*p = ~*p--;
	}
}

void InitRand(int seed)
{
	//seed %= 0xFF;
	//while(seed--)
	//	rand();
}

/*****************************************************************************/

int Accumulate(int a, int b, int op)
{
	switch(op%9)
	{
	case 0:
	case 1:
	case 2:
		return a + b;
	case 3:
		return a - b;
	case 4:
		return a * b;
	case 5:
		return !a ? b : a / b;	// ensure a != 0
	case 6:
		return a % b;
	case 7:
		return a & b;
	default:
		return a | b;
	}
}

int CalculateHip(char* buf, int len)
{
	// a + b + c + d
	int x = 0;
	int op = 0;

	for(int i=0; i<len; i++)
	{
		if(i%2)
		{
			op = buf[i];
		}
		else
		{
			x = Accumulate(x, buf[i], op);
		}
	}

	return x;
}

int BuildHipFormular(char* buf, int len)
{
	GUID uid;
	CoCreateGuid(&uid);
	char* p = buf, *q = (char*)&uid;	// a + b + c + d
	int n = len;

	while(n--)
	{
		*p++ = *q++;
	}

	return CalculateHip(buf, len);
}

/*****************************************************************************/

//class RijndaelCrypto : public ISymmetricCrypto
//{
//public:
//	virtual bool setCipher(const unsigned char* cihper, const int length) = 0;
//	virtual bool encrypt(const unsigned char* input, const int length, unsigned char* output) = 0;
//	virtual bool decrypt(const unsigned char* input, const int length, unsigned char* output) = 0;
//};

RijndaelCrypto::RijndaelCrypto(bool encrypt)
	: m_encrypt(encrypt)
{
}

bool RijndaelCrypto::setCipher(const unsigned char* cipher, const int length)
{
	if(!cipher)
		return false;

	if(length != 16)
		return false;

	if(m_encrypt)
	{
		int	hr = rijndaelKeySetupEnc(m_rk, cipher, 128);
		return hr == 10;
	}
	else
	{
		int	hr = rijndaelKeySetupDec(m_rk, cipher, 128);
		return hr == 10;
	}

	return false;
}

bool RijndaelCrypto::encrypt(const unsigned char* input, const int length, unsigned char* output)
{
	if(length != 16)
		return false;

	rijndaelEncrypt(m_rk, 10, input, output);
	return true;
}

bool RijndaelCrypto::decrypt(const unsigned char* input, const int length, unsigned char* output)
{
	if(length != 16)
		return false;

	rijndaelDecrypt(m_rk, 10, input, output);
	return true;
}

/*
class ShiningloreCryptoCache
{
public:
	static std::shared_ptr<ISymmetricCrypto> getRijndaelEncrypter();
	static std::shared_ptr<ISymmetricCrypto> getRijndaelDecrypter();

private:
	static std::shared_ptr<ISymmetricCrypto> m_encrypter;
	static std::shared_ptr<ISymmetricCrypto> m_decrypter;
};
*/

using namespace std;

shared_ptr<ISymmetricCrypto> ShiningloreCryptoCache::s_encrypter;
shared_ptr<ISymmetricCrypto> ShiningloreCryptoCache::s_decrypter;

// NOTE: it is not thread safty
shared_ptr<ISymmetricCrypto>ShiningloreCryptoCache::getRijndaelEncrypter()
{
	if(!s_encrypter)
	{
		s_encrypter.reset(new RijndaelCrypto(true));
		s_encrypter->setCipher(cipher, 16);
	}
	return s_encrypter;
}

// NOTE: it is not thread safty
shared_ptr<ISymmetricCrypto>ShiningloreCryptoCache::getRijndaelDecrypter()
{
	if(!s_decrypter)
	{
		s_decrypter.reset(new RijndaelCrypto(false));
		s_decrypter->setCipher(cipher, 16);
	}
	return s_decrypter;
}

////
shared_ptr<CFileVersion> ShiningloreVersionCache::s_t509;
shared_ptr<CFileVersion> ShiningloreVersionCache::s_x509;

// NOTE: it is not thread safty
shared_ptr<CFileVersion> ShiningloreVersionCache::getT509Ver()
{
	if(!s_t509)
	{
		s_t509.reset(CFileVersion::GetVersionPtr(L"T509"));
	}
	return s_t509;
}

// NOTE: it is not thread safty
shared_ptr<CFileVersion> ShiningloreVersionCache::getX509Ver()
{
	if(!s_x509)
	{
		s_x509.reset(CFileVersion::GetVersionPtr(L"X509"));
	}
	return s_x509;
}